################################################################################################
# Generic Makefile for STM32F407VGT6 (GCC)
################################################################################################

# 目标名称
TARGET = template

# 构建选项
DEBUG = 1
OPT   = -Og

# 构建目录
BUILD_DIR = build

# 工具链前缀
PREFIX  = arm-none-eabi-

# 工具定义
CC      = $(PREFIX)gcc
CXX     = $(PREFIX)g++
AS      = $(PREFIX)gcc -x assembler-with-cpp
CP      = $(PREFIX)objcopy
SZ      = $(PREFIX)size
HEX     = $(CP) -O ihex
BIN     = $(CP) -O binary -S
GDB     = $(PREFIX)gdb

######################################
# 源文件
######################################
# 使用更精确的文件查找方式，避免包含不需要的文件
C_SOURCES = \
$(wildcard ./CMSIS/*.c) \
$(wildcard ./Library/src/*.c) \
$(wildcard ./Start/*.c) \
$(wildcard ./User/src/*.c)

# 汇编源文件
ASM_SOURCES = ./CMSIS/startup_stm32f407xx.s

######################################
# 编译选项
######################################
# MCU 选项
CPU        = -mcpu=cortex-m4
FPU        = -mfpu=fpv4-sp-d16 -mfloat-abi=hard
MCU        = $(CPU) -mthumb $(FPU)

# C 定义
C_DEFS = \
-DSTM32F40_41xxx \
-DUSE_STDPERIPH_DRIVER \
-DHSE_VALUE=8000000 \
-D__weak="__attribute__((weak))" \
-D__packed="__attribute__((__packed__))"

# 包含路径
C_INCLUDES = \
-ICMSIS \
-ILibrary/inc \
-IStart \
-IUser/inc

# 汇编标志
ASFLAGS  = $(MCU) $(OPT) -Wall -fdata-sections -ffunction-sections

# C 标志
CFLAGS   = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

# 调试选项
ifeq ($(DEBUG), 1)
CFLAGS  += -g -gdwarf-2
endif

# 依赖生成
CFLAGS  += -MMD -MP -MF"$(@:%.o=%.d)"

# C++ 标志
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti -fno-threadsafe-statics -fno-use-cxa-atexit

# 链接时优化 (可选)
# LTO_FLAGS = -flto

######################################
# 链接选项
######################################
LDSCRIPT = STM32F407VGTx_FLASH.ld
LIBS     = -lc -lm -lnosys -lstdc++
LDFLAGS  = $(MCU) -specs=nano.specs -specs=nosys.specs -T$(LDSCRIPT) $(LIBS) \
           -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections \
           -Wl,--print-memory-usage

# 可选: 移除未使用段以减小代码大小
# LDFLAGS += -Wl,--gc-sections

######################################
# 构建目标
######################################
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

# 对象文件列表
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))

OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))

# C 编译规则
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
	@echo "Compiling $<"
	@$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

# 汇编编译规则
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
	@echo "Assembling $<"
	@$(AS) -c $(CFLAGS) $< -o $@

# 链接规则
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	@echo "Linking $@"
	@$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	@echo "=== Build completed ==="
	@$(SZ) $@
	@echo "Memory usage:"
	@arm-none-eabi-size --format=sysv $@

# 生成 HEX 文件
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	@$(HEX) $< $@

# 生成 BIN 文件
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	@$(BIN) $< $@

# 创建构建目录
$(BUILD_DIR):
	@mkdir -p $@

######################################
# 清理规则
######################################
ifeq ($(OS),Windows_NT)
    RM = rmdir /S /Q
else
    RM = rm -rf
endif
clean:
	-$(RM) $(BUILD_DIR)

######################################
# 烧录和调试
######################################
# OpenOCD 烧录
OPENOCD = openocd
OPENOCD_SCRIPT_DIR = D:/SoftWare/Environment/openocd/scripts
OPENOCD_INTERFACE = stlink-v2.cfg
OPENOCD_TARGET = stm32f4x.cfg

download:
	$(OPENOCD) -f $(OPENOCD_SCRIPT_DIR)/interface/$(OPENOCD_INTERFACE) \
	           -f $(OPENOCD_SCRIPT_DIR)/target/$(OPENOCD_TARGET) \
	           -c init -c halt \
	           -c "program $(BUILD_DIR)/$(TARGET).elf verify reset exit"

# J-Link 烧录
JLINK = "C:/Program Files/SEGGER/JLink_V856a/JLink.exe"
JLINK_DEVICE = STM32F407VG
JLINK_IF = SWD
JLINK_SPEED = 4000

jlink:
	@echo "Generating J-Link script..."
	@echo "r" > temp_script.jlink
	@echo "h" >> temp_script.jlink
	@echo "loadfile $(BUILD_DIR)/$(TARGET).hex" >> temp_script.jlink
	@echo "r" >> temp_script.jlink
	@echo "q" >> temp_script.jlink
	@echo "Flashing with J-Link..."
	@$(JLINK) -device $(JLINK_DEVICE) -if $(JLINK_IF) -speed $(JLINK_SPEED) -CommanderScript temp_script.jlink
	@rm -f temp_script.jlink
	@echo "=== Flash completed ==="

# 调试
debug:
	@echo "r" > temp_debug.jlink
	@echo "h" >> temp_debug.jlink
	@echo "loadfile $(BUILD_DIR)/$(TARGET).elf" >> temp_debug.jlink
	@echo "r" >> temp_debug.jlink
	@echo "g" >> temp_debug.jlink
	@$(JLINK) -device $(JLINK_DEVICE) -if $(JLINK_IF) -speed $(JLINK_SPEED) -CommanderScript temp_debug.jlink
	@rm -f temp_debug.jlink

# GDB 调试 (可选)
gdb:
	$(GDB) $(BUILD_DIR)/$(TARGET).elf -ex "target extended-remote :3333"

# 依赖包含
-include $(wildcard $(BUILD_DIR)/*.d)

# 显示帮助信息
help:
	@echo "=== Makefile 帮助 ==="
	@echo "make all       - 构建所有目标 (默认)"
	@echo "make clean     - 清理构建文件"
	@echo "make download  - 使用 OpenOCD 烧录"
	@echo "make jlink     - 使用 J-Link 烧录"
	@echo "make debug     - 使用 J-Link 调试"
	@echo "make gdb       - 启动 GDB 调试"
	@echo "make help      - 显示此帮助信息"

.PHONY: all clean download jlink debug gdb help